import multiprocessing

from .common_func.print_logger import PrintLogger as Logger
import_error_warned = False
try:
    import redis
except ModuleNotFoundError:
    if not import_error_warned:
        Logger.warning("URedis is not valid, because require module:[redis] is not installed. "
                       "If you want use URedis, please install [redis] first")
        import_error_warned = True

from .u_exception import exception_capture_decorator, ErrorLogger

class URedis:
    """redis连接"""

    def __init__(self, redis_config: dict, logger) -> None:
        self.db_name = int(redis_config.get("db", 0))
        self.passwd = redis_config.get("password")
        self.host = redis_config.get("host")
        self.port = redis_config.get("port")
        self.conn = self._connect()
        cur_process = multiprocessing.current_process()
        logger_name = cur_process.name
        if logger is not None:
            ErrorLogger.add_logger(logger_name, logger)

    def __del__(self):
        self.conn.close()

    def _connect(self):
        conn = redis.Redis(host=self.host, port=self.port, db=self.db_name, password=self.passwd)
        return conn

    @exception_capture_decorator(_return=False)
    def ping(self):
        return bool(self.conn.ping())

    @exception_capture_decorator()
    def select(self, db_id):
        """
        切换数据库
        """
        self.conn.select(db_id)

    # 删除键
    @exception_capture_decorator()
    def del_key(self, key):
        self.conn.delete(key)

    # 批量删除键
    @exception_capture_decorator()
    def del_keys(self, keys):
        self.conn.delete(*keys)

    # 模糊查找key
    @exception_capture_decorator(_return=[])
    def find_keys(self, pattern):
        result = []
        cursor, keys = self.conn.scan(match=pattern, count=1000)
        if keys:
            result = keys

        while cursor:
            cursor, keys = self.conn.scan(cursor=cursor, match=pattern, count=1000)
            if keys:
                result.extend(keys)
        return result

    # 判断key是否存在
    @exception_capture_decorator(_return=False)
    def is_key_exist(self, key):
        return self.conn.exists(key)

    # 设置键值对，但不提供过期时间的选项
    @exception_capture_decorator(_return=None)
    def str_set(self, key, val):
        self.conn.set(key, val)

    # 获取键的值，如果键存在返回键值，如果不存在，则返回nil
    @exception_capture_decorator(_return=None)
    def str_get(self, key):
        return self.conn.get(key)

    # 字符串添加 设置键值对,提供过期时间的选项
    @exception_capture_decorator(_return=None)
    def str_time_set(self, key, val, time):
        self.conn.set(key, val, ex=time)

    # 列表,从类别左侧进
    @exception_capture_decorator(_return=None)
    def l_push(self, key, value):
        self.conn.lpush(key, value)

    @exception_capture_decorator(_return=None)
    def l_pop_many(self, key, size):
        """
        该函数仅支持redis >=6.2.0
        """
        return self.conn.lpop(key, size)

    # 从列表右侧进
    @exception_capture_decorator(_return=None)
    def r_push(self, key, value):
        self.conn.rpush(key, value)

    @exception_capture_decorator(_return=None)
    def r_push_many(self, key, *value):
        self.conn.rpush(key, *value)

    # 列表长度
    @exception_capture_decorator(_return=None)
    def t_len(self, key):
        return self.conn.llen(key)

    # 从右侧移除一个元素并返回对应值
    @exception_capture_decorator(_return=None)
    def r_pop(self, key):
        return self.conn.rpop(key)

    # 获取列表中所有值
    @exception_capture_decorator(_return=None)
    def all_list(self, key):
        return self.conn.lrange(key, 0, -1)

    # 有侧开始删除n个值
    @exception_capture_decorator(_return=None)
    def rem_n_value(self, key, count, value):
        return self.conn.lrem(key, -count, value)

    # hash
    # 添加
    @exception_capture_decorator(_return=None)
    def hash_add(self, p_key, key, v):
        self.conn.hset(p_key, key, v)

    # 删除
    @exception_capture_decorator(_return=None)
    def hash_del(self, p_key, key):
        self.conn.hdel(p_key, key)

    # 检查key是否存在
    @exception_capture_decorator(_return=None)
    def check_key_exist(self, p_key, key):
        return self.conn.hexists(p_key, key)

    @exception_capture_decorator(_return=None)
    def set_hash_add_exp_time(self, p_key, exp_time):
        self.conn.expire(p_key, exp_time)

    # 一次添加多个field
    @exception_capture_decorator(_return=None)
    def hash_add_many_fields(self, p_key, fields: dict):
        self.conn.hmset(p_key, fields)

    # 一次添加多个key及对应的fields
    @exception_capture_decorator(_return=None)
    def hash_add_many_keys_fields(self, p_keys_fields: dict):
        pipe = self.conn.pipeline()
        for k, v in p_keys_fields.items():
            pipe.hmset(k, v)
        pipe.execute()

    # 单个
    @exception_capture_decorator(_return=None)
    def hash_get(self, p_key, key):
        return self.conn.hget(p_key, key)

    @exception_capture_decorator(_return=None)
    def hash_len(self, key_value):
        return self.conn.hlen(key_value)

    # 获取所有
    @exception_capture_decorator(_return=None)
    def hash_get_all(self, p_key):
        return self.conn.hgetall(p_key)

    # h set nx 给哈希表key添加field-value对，当且仅当域field不存在
    @exception_capture_decorator(_return=None)
    def hash_set_nx(self, p_key, key, v):
        self.conn.hsetnx(p_key, key, v)

    #     increase by 为哈希表key中的域field的值加上<increment>
    @exception_capture_decorator(_return=None)
    def hash_increase_by(self, p_key, key, count):
        self.conn.hincrby(p_key, key, count)
        # 删除hash中的指定字段, 字段对应的值会一起删除

    @exception_capture_decorator(_return=None)
    def hash_del(self, p_key, key):
        self.conn.hdel(p_key, key)

    # set nx键不存在时设置键的值，如果键存在，它不进行任何操作。
    @exception_capture_decorator(_return=None)
    def str_set_nx(self, key, v):
        return self.conn.setnx(key, v)

    # set_ex设置键值对，并为键值对设置过期时间，如果键已经存在，它将被更新；如果不存在，它将被创建。
    @exception_capture_decorator(_return=None)
    def str_set_ex(self, key, expiration_time, v):
        return self.conn.setex(key, expiration_time, v)

    # 模糊查找某个key的具体值
    @exception_capture_decorator(_return=None)
    def get_keys_len(self, key_pattern):
        keys = self.conn.scan(match=key_pattern)
        return len(keys[1])

    @exception_capture_decorator(_return=None)
    def store_change(self, key, count, _type):
        # type 1加 2减
        if _type == 1:
            self.conn.decrby(key, count)
        else:
            self.conn.incrby(key, count)

    #     set
    @exception_capture_decorator(_return=None)
    def set_add(self, k, v):
        self.conn.sadd(k, v)

    @exception_capture_decorator(_return=None)
    def set_add_members(self, k, members):
        pipe = self.conn.pipeline()
        for i in members:
            pipe.sadd(k, i)
        pipe.execute()

    @exception_capture_decorator(_return=None)
    def set_del_member(self, k, v):
        self.conn.srem(k, v)

    @exception_capture_decorator(_return=False)
    def set_exist_member(self, k, v):
        return self.conn.sismember(k, v)

    @exception_capture_decorator(_return=None)
    def set_get_all(self, k):
        return self.conn.smembers(k)

    @exception_capture_decorator(_return=None)
    def set_del(self, k):
        return self.conn.delete(k)

    @exception_capture_decorator(_return=None)
    def get_memory_usage(self, key):
        """
        获取key对应的字节数
        """
        return self.conn.memory_usage(key)

    @exception_capture_decorator(_return=None)
    def set_reset(self, k, members):
        """
            清空set并重新插入数据
        """
        pipe = self.conn.pipeline()
        pipe.delete(k)
        for i in members:
            pipe.sadd(k, i)
        pipe.execute()

    @exception_capture_decorator(_return=None)
    def add_many_set(self, sets: dict):
        """
        批量插入多个set结构的数据
        """
        pipe = self.conn.pipeline()
        for k, v in sets.items():
            pipe.sadd(k, *v)
        pipe.execute()

    @exception_capture_decorator(_return=None)
    def add_by_hincrby(self, key_v, field_v):
        """
        主要用于对hash表中的字段值递增，原子性的方式修改表中字段
        """
        self.conn.hincrby(key_v, field_v)

    @exception_capture_decorator(_return='redis_exception')
    def hash_get_with_exception(self, p_key, key):
        return self.conn.hget(p_key, key)


